package com.xltt.bluetoothlib.ble;

import android.annotation.TargetApi;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;

import com.xltt.bluetoothlib.ble.event.OnChangeEvent;
import com.xltt.bluetoothlib.ble.utils.BleUtils;
import com.xltt.bluetoothlib.ble.utils.Command;
import com.xltt.bluetoothlib.ble.utils.HexUtil;


import java.util.Arrays;
import java.util.UUID;

public class BleManager extends BaseBleManager{


    public static final String TAG = "zhanghui";

    private Context mContext;
    private BluetoothLeAdvertiser mBluetoothLeAdvertiser; // BLE广播
    private BluetoothGattServer mBluetoothGattServer; // BLE服务端
    private BluetoothGattService mBluetoothGattService;
    public DataPackage.OnDataPackageListener mOnDataPackageListener;

    private static volatile BleManager instance = null;
    private BleManager(Context context) {
        this.mContext = context;
    }

    //运行时加载对象
    public static BleManager getInstance(Context context) {
        if (instance == null) {
            synchronized(BleManager.class){
                if(instance == null){
                    instance = new BleManager(context);
                }
            }
        }
        return instance;
    }




        /**
     * 启动gatt 服务
     */
    public BleManager initGattService(){

        if(mBluetoothGattService == null){
            Log.i(TAG,"初始化， gatt server " );
            mBluetoothGattService = new BluetoothGattService(UUID_SERVICE, BluetoothGattService.SERVICE_TYPE_PRIMARY);
            //添加可读characteristic
            BluetoothGattCharacteristic characteristicRead = new BluetoothGattCharacteristic(UUID_CHAR_READ,
                    BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ);
            mBluetoothGattService.addCharacteristic(characteristicRead);

            //添加可写characteristic
            BluetoothGattCharacteristic characteristicWrite = new BluetoothGattCharacteristic(UUID_CHAR_WRITE,
                    BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE);
            mBluetoothGattService.addCharacteristic(characteristicWrite);

            //添加可通知characteristic
            BluetoothGattCharacteristic characteristicNotify = new BluetoothGattCharacteristic(UUID_DESC_NOTITY,
                    BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ);
            mBluetoothGattService.addCharacteristic(characteristicNotify);



            BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
            if (bluetoothManager != null){
                mBluetoothGattServer = bluetoothManager.openGattServer(mContext, mBluetoothGattServerCallback);
            }
            if(mBluetoothGattServer != null){
                mBluetoothGattServer.addService(mBluetoothGattService);
            }
        }
        Log.i(TAG,"初始化，广播配置 " );
        // ============启动BLE蓝牙广播(广告) =================================================================================
        //广播设置(必须)
        startAdvertising();
        return this;
    }


    public void startAdvertising(){
        // ============启动BLE蓝牙广播(广告) =================================================================================
        //广播设置(必须)
        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED) //广播模式: 低功耗,平衡,低延迟
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) //发射功率级别: 极低,低,中,高
                .setTimeout(0)
                .setConnectable(true) //能否连接,广播分为可连接广播和不可连接广播
                .build();
        //广播数据(必须，广播启动就会发送)
        AdvertiseData advertiseData = new AdvertiseData.Builder()
                .setIncludeDeviceName(true) //包含蓝牙名称
                .setIncludeTxPowerLevel(true) //包含发射功率级别
                .addManufacturerData(1, new byte[]{23, 33}) //设备厂商数据，自定义
                .build();
        mBluetoothLeAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
        mBluetoothLeAdvertiser.startAdvertising(settings, advertiseData, null, mAdvertiseCallback);
        Log.i(TAG,"启动，广播 " );
    }

    public void stopAdvertising(){
        if(mBluetoothLeAdvertiser != null){
            mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
            mBluetoothLeAdvertiser = null;
            Log.i(TAG,"销毁，广播 " );
        }
    }

    /**
     * 停止gatt服务
     */
    public BleManager destroyGattService(){
        if(mBluetoothLeAdvertiser != null){
            mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
            mBluetoothLeAdvertiser = null;
            Log.i(TAG,"销毁，广播 " );
        }
        if(mBluetoothGattServer != null){
            mBluetoothGattServer.clearServices();
            mBluetoothGattServer.close();
            mBluetoothGattServer = null;
            mBluetoothGattService = null;
            mOnDataPackageListener = null;
            Log.i(TAG,"销毁，gatt server " );
        }
        return this;

    }


    /**
     * 发送数据
     * @param value
     * @return
     */
    public boolean sendClientData(byte[] value){
        if(mConnectDevice == null || mBluetoothGattServer == null || mBluetoothGattService == null){
            Log.e(TAG,"send client data error " );
            return false;
        }
        BluetoothGattCharacteristic mNotifyCharacteristic = mBluetoothGattService.getCharacteristic(UUID_DESC_NOTITY);
        mNotifyCharacteristic.setValue(value);
        return mBluetoothGattServer.notifyCharacteristicChanged(mConnectDevice,mNotifyCharacteristic,false);
    }




    public BleManager setDataPackageListent(DataPackage.OnDataPackageListener dataPackageListener){
        this.mOnDataPackageListener = dataPackageListener;
        return this;
    }

    private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            Log.i(TAG,"BLE广播开启成功,名称 = " + BluetoothAdapter.getDefaultAdapter().getName());
        }

        @Override
        public void onStartFailure(int errorCode) {
            Log.i(TAG,"BLE广播开启 失败,错误码:" + errorCode);
        }
    };

    private BluetoothDevice mConnectDevice;
    private BluetoothGattServerCallback mBluetoothGattServerCallback = new BluetoothGattServerCallback() {
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
            Log.i(TAG, String.format("onConnectionStateChange:%s,%s,%s,%s", device.getName(), device.getAddress(), status, newState));
            Log.i(TAG, String.format(status == 0 ? (newState == 2 ? "与[%s]连接成功" : "与[%s]连接断开") : ("与[%s]连接出错,错误码:" + status), device));
            mConnectDevice = device;
            if(mOnDataPackageListener != null){
                mOnDataPackageListener.onConnectionStateChange(device,status,newState);
            }
        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            Log.i(TAG, String.format("onServiceAdded:%s,%s", status, service.getUuid()));
            Log.i(TAG, String.format(status == 0 ? "添加服务[%s]成功" : "添加服务[%s]失败,错误码:" + status, service.getUuid()));
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
            Log.i(TAG, String.format("onCharacteristicReadRequest:%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, offset, characteristic.getUuid()));
            String response = "CHAR_" + (int) (Math.random() * 100); //模拟数据
            mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, response.getBytes());// 响应客户端
            Log.i(TAG,"客户端读取Characteristic[" + characteristic.getUuid() + "]:\n" + response);
        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
            // 获取客户端发过来的数据
            String requestStr = new String(requestBytes);
            Log.i(TAG, String.format("onCharacteristicWriteRequest:%s,%s,%s,%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, characteristic.getUuid(),
                    preparedWrite, responseNeeded, offset, requestStr));
            mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, requestBytes);// 响应客户端
            if(mOnDataPackageListener != null){
                mOnDataPackageListener.OnDataPackage(new OnChangeEvent(device,requestId,characteristic,preparedWrite,responseNeeded,offset,requestBytes));
            }

            Log.i(TAG, "客户端写入Characteristic[" + characteristic.getUuid() + "]:\n" + requestStr + ",长度 = " + requestBytes.length + ",mOnDataPackageListener = " + mOnDataPackageListener);
        }

        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
            Log.i(TAG, String.format("onDescriptorReadRequest:%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, offset, descriptor.getUuid()));
            String response = "DESC_" + (int) (Math.random() * 100); //模拟数据
            mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, response.getBytes()); // 响应客户端
            Log.i(TAG, "客户端读取Descriptor[" + descriptor.getUuid() + "]:\n" + response);
        }

        @Override
        public void onDescriptorWriteRequest(final BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            // 获取客户端发过来的数据
            String valueStr = Arrays.toString(value);
            Log.i(TAG, String.format("onDescriptorWriteRequest:%s,%s,%s,%s,%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, descriptor.getUuid(),
                    preparedWrite, responseNeeded, offset, valueStr));
            Log.i(TAG, "客户端写入Descriptor[" + descriptor.getUuid() + "]:\n" + valueStr);
            mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);// 响应客户端

        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            Log.i(TAG, String.format("onExecuteWrite:%s,%s,%s,%s", device.getName(), device.getAddress(), requestId, execute));
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            Log.i(TAG, String.format("onNotificationSent:%s,%s,%s", device.getName(), device.getAddress(), status));
            if(status == BluetoothGatt.GATT_SUCCESS){
                Log.i(TAG, "给设备 = " + device.getAddress() + " 发送通知成功，操作更新UI");
            }else{
                Log.i(TAG, "给设备 = " + device.getAddress() + " 发送通知失败，status = " + status);
            }
            super.onNotificationSent(device, status);
        }

        @Override
        public void onMtuChanged(BluetoothDevice device, int mtu) {
            Log.i(TAG, String.format("onMtuChanged:%s,%s,%s", device.getName(), device.getAddress(), mtu));
        }
    };
}
